home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp95 / freyja_t.z / freyja_t / buf.c < prev    next >
C/C++ Source or Header  |  1992-04-14  |  43KB  |  2,044 lines

  1. /* BUF.C -- Buffer Managment
  2.  
  3.     Written March 1991 by Craig A. Finseth
  4.     Copyright 1991 by Craig A. Finseth
  5. */
  6.  
  7. #include "freyja.h"
  8.  
  9. #if defined(UNIX)
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #endif
  13.  
  14. #define ZCK    '\013'        /* ^K */
  15.  
  16. struct phys_page {
  17.     char page_data[PAGESIZE];    /* the page */
  18.     struct phys_page *next;        /* LRU chain */
  19.     struct phys_page *prev;
  20.     char page_loc;            /* logical location of page */
  21.     int page_num;
  22.     FLAG is_mod;            /* is the page dirty? */
  23.     struct virt_page *pptr;        /* page description for this page */
  24.     };
  25.  
  26.  
  27.     /* cached information on the current page */
  28. static struct virt_page *cur_page;    /* virtual page */
  29. static int cur_pt_offset;        /* point offset */
  30. static int cur_page_len;        /* page length */
  31. static char *cur_cptr;            /* actual character */
  32. static char *cur_page_start;        /* start of the page */
  33. static char *cur_gap_start;        /* position of the gap */
  34. static char *cur_gap_end;
  35. static FLAG cur_is_mod;            /* is modified (dirty) */
  36. static int cur_col = -1;        /* current column position */
  37.  
  38. static int savecol;
  39. struct mark *getmark;
  40.  
  41. static struct virt_page vp[SWAPMAX];
  42.  
  43. static struct mark marks[MAXMARK];
  44. #define MAXSMARK    (sizeof(screenmarks) / sizeof(screenmarks[0]))
  45. static struct mark screenmarks[ROWMAX + 2];
  46.  
  47. #if defined(MSDOS)
  48. static unsigned swap_base;
  49. #else
  50. static char *swap_base;
  51. #endif
  52.  
  53. static struct phys_page pages[NUM_PHYS_PAGES];    /* page descriptors */
  54.  
  55. static struct phys_page *first_phys_page;  /* LRU chain of pages in memory */
  56. static struct phys_page *last_phys_page;
  57.  
  58. #define SWAPMAPSIZE    ((long)SWAPMAX * 1024 / PAGESIZE)
  59. static char swap_map[SWAPMAPSIZE];    /* swap file in use flags */
  60. static int num_swap;            /* number of swap file pages */
  61.  
  62.  
  63.  
  64. void B_FileReadCheck();        /* void */
  65. void B_GetGap();        /* void */
  66. int B_IndexB();            /* char *array, int len, char chr */
  67. int B_IndexF();            /* char *array, int len, char chr */
  68. FLAG B_InsChar();        /* char new */
  69. void B_MarkUpdate();        /* struct virt_page *new_page, int amt,
  70.                 int new_offset */
  71. void B_MarkUpdateNP();        /* struct virt_page *new_page,
  72.                 int new_offset */
  73. void B_MovePointTo();        /* int dist */
  74. struct virt_page * B_PageAllocate();    /* struct buffer *bptr;
  75.             struct virt_page *prev, struct virt_page *next */
  76. struct phys_page *B_PageFindFree();    /* void */
  77. void B_PageFree();        /* struct buffer *bptr,
  78.                 struct virt_page *pptr */
  79. FLAG B_PageSplit();        /* int amount */
  80. void B_PageToMemory();        /* struct virt_page *pptr */
  81. void B_PageToCurrent();        /* struct virt_page *pptr */
  82. void B_RulerLine();        /* void */
  83. void B_SetScreenMarks();    /* FLAG newflag */
  84. void B_SetScreenMarks2();    /* struct window *wptr, FLAG newflag */
  85.  
  86. /* ------------------------------------------------------------ */
  87.  
  88. /* Initialize the buffer abstraction.  Return TRUE on success or FALSE
  89. on failure. */
  90.  
  91. FLAG
  92. BInit(swap_size)
  93.     int swap_size;
  94.     {
  95.     struct phys_page *pptr;
  96.     int cnt;
  97.  
  98.     cbuf = NULL;
  99.     cur_page = NULL;
  100.     for (pptr = pages; pptr < &pages[NUM_PHYS_PAGES]; ++pptr) {
  101.         pptr->page_loc = 'M';
  102.         pptr->is_mod = FALSE;
  103.         pptr->next = pptr + 1;
  104.         pptr->prev = pptr - 1;
  105.         }
  106.     first_phys_page = pages;
  107.     first_phys_page->prev = NULL;
  108.     last_phys_page = pptr - 1;
  109.     last_phys_page->next = NULL;
  110.  
  111.     getmark = BMarkCreate();
  112.  
  113.     for (cnt = 0; cnt < MAXMARK; cnt++) marks[cnt].pptr = NULL;
  114.     for (cnt = 0; cnt < MAXSMARK; cnt++) screenmarks[cnt].pptr = NULL;
  115.     for (cnt = 0; cnt < NUMBUFFERS; cnt++) buffers[cnt].num_pages = 0;
  116.  
  117.     for (cnt = 0; cnt < SWAPMAPSIZE; cnt++) swap_map[cnt] = 0;
  118.     num_swap = ((long)swap_size * 1024) / PAGESIZE;
  119.  
  120. #if defined(MSDOS)
  121.     /* 64 = 1024 / 16 */
  122.     swap_base = BlockAlloc(swap_size * 64);
  123.     return(swap_base != 0);
  124. #endif
  125. #if defined(UNIX)
  126.     swap_base = (char *)malloc(swap_size * 1024);
  127.     return(swap_base != NULL);
  128. #endif
  129.     }
  130.  
  131.  
  132. /* ------------------------------------------------------------ */
  133.  
  134. /* Terminate the buffer abstraction. */
  135.  
  136. void
  137. BFini()
  138.     {
  139. #if defined(MSDOS)
  140.     BlockFree(swap_base);
  141. #endif
  142. #if defined(UNIX)
  143.     free(swap_base);
  144. #endif
  145.     }
  146.  
  147.  
  148. /* ------------------------------------------------------------ */
  149.  
  150. /* Create a buffer. Returns a pointer to the buffer descriptor or NULL. */
  151.  
  152. struct buffer *
  153. BBufCreate(fname)
  154.     char *fname;
  155.     {
  156.     int cnt;
  157.     struct buffer *bptr;
  158.  
  159.     for (cnt = 0; cnt < NUMBUFFERS && !BIsFree(&buffers[cnt]); cnt++) ;
  160.     if (cnt >= NUMBUFFERS) {
  161.         DError("No free buffers");
  162.         return(NULL);
  163.         }
  164.     bptr = &buffers[cnt];
  165.  
  166.         /* copy parameters from previous buffer */
  167.     bptr->c = (cbuf == NULL) ? c.d : cbuf->c;
  168.  
  169.     xstrcpy(bptr->fname, fname);
  170.     bptr->num_pages = 0;
  171.     bptr->is_mod = FALSE;
  172.     bptr->point_offset = 0;
  173.     bptr->mptr = NULL;
  174.  
  175.     if ((bptr->point_page = B_PageAllocate(bptr, NULL, NULL)) == NULL)
  176.         return(NULL);
  177.     B_PageToMemory(bptr->point_page);
  178.  
  179.     BBufGoto(bptr);
  180.     bptr->mptr = BMarkCreate();
  181.     mark = bptr->mptr;
  182.     return(bptr);
  183.     }
  184.  
  185.  
  186. /* ------------------------------------------------------------ */
  187.  
  188. /* Delete the buffer and all associated pages.  If no non-system
  189. buffers are left, re-create scratch. */
  190.  
  191. void
  192. BBufDelete(delptr)
  193.     struct buffer *delptr;
  194.     {
  195.     struct buffer *bptr;
  196.  
  197.     if (delptr == cbuf || delptr == NULL) {
  198.         DError("Can't delete the current buffer");
  199.         return;
  200.         }
  201.     if (strequ(delptr->fname, SYS_KILL)) {
  202.         DError("Can't delete the kill buffer");
  203.         return;
  204.         }
  205.     if (strequ(delptr->fname, SYS_SCRATCH)) {
  206.         DError("Can't delete the scratch buffer");
  207.         return;
  208.         }
  209.     while (delptr->first != NULL) B_PageFree(delptr, delptr->first);
  210.     delptr->num_pages = 0;
  211.  
  212.     for (bptr = buffers; bptr < &buffers[NUMBUFFERS]; bptr++) {
  213.         if (!BIsFree(bptr) && (!IS_SYS(bptr->fname) ||
  214.              strequ(bptr->fname, SYS_SCRATCH)))
  215.             return;
  216.         }
  217.     BBufCreate(SYS_SCRATCH);
  218.     }
  219.  
  220.  
  221. /* ------------------------------------------------------------ */
  222.  
  223. /* Locate a buffer with a buffer name of exactly NAME (preferred) or
  224. starting with NAME (backup). */
  225.  
  226. struct buffer *
  227. BBufFind(name)
  228.     char *name;
  229.     {
  230.     struct buffer *bptr;
  231.  
  232.     for (bptr = cbuf + 1; 1; bptr++) {
  233.         if (bptr >= &buffers[NUMBUFFERS]) bptr = buffers;
  234.         if (!BIsFree(bptr) && strequ(name, bptr->fname)) return(bptr);
  235.         if (bptr == cbuf) break;
  236.         }
  237.  
  238.     for (bptr = cbuf + 1; 1; bptr++) {
  239.         if (bptr >= &buffers[NUMBUFFERS]) bptr = buffers;
  240.         if (!BIsFree(bptr) && strnequ(name, bptr->fname, strlen(name)))
  241.             return(bptr);
  242.         if (bptr == cbuf) break;
  243.         }
  244.     return(NULL);
  245.     }
  246.  
  247.  
  248. /* ------------------------------------------------------------ */
  249.  
  250. /* Switch to the specified buffer. */
  251.  
  252. void
  253. BBufGoto(bptr)
  254.     struct buffer *bptr;
  255.     {
  256.     if (bptr == NULL || bptr->num_pages == 0) {
  257.         DError("Not a buffer");
  258.         return;
  259.         }
  260.     if (cbuf != NULL) {
  261.         cbuf->point_page = cur_page;
  262.         cbuf->point_offset = cur_pt_offset;
  263.         }
  264.     B_PageToCurrent(bptr->point_page);
  265.     B_MovePointTo(bptr->point_offset);
  266.     cbuf = bptr;
  267.     cur_col = -1;
  268.     mark = cbuf->mptr;
  269.     }
  270.  
  271.  
  272. /* ------------------------------------------------------------ */
  273.  
  274. /* Clear the current buffer's modified flag. */
  275.  
  276. void
  277. BBufUnmod()
  278.     {
  279.     cbuf->is_mod = FALSE;
  280.     }
  281.  
  282.  
  283. /* ------------------------------------------------------------ */
  284.  
  285. /* Change the current character to TO. */
  286.  
  287. void
  288. BCharChange(to)
  289.     char to;
  290.     {
  291.     if (!BIsEnd()) {
  292.         *cur_cptr = to;
  293.         cbuf->is_mod = TRUE;
  294.         cur_is_mod = TRUE;
  295.         B_SetScreenMarks(FALSE);
  296.         BMoveBy(1);
  297.         }
  298.     else    BInsChar(to);
  299.     }
  300.  
  301.  
  302. /* ------------------------------------------------------------ */
  303.  
  304. /* Delete AMOUNT characters.  If AMOUNT is negative, delete backwards. */
  305.  
  306. void
  307. BCharDelete(amount)
  308.     int amount;
  309.     {
  310.     int num = amount;
  311.     int tmp;
  312.     struct mark *mptr;
  313.     struct virt_page *vpage;
  314.  
  315.     if (amount == 0) return;
  316.     B_GetGap();
  317.  
  318.     if (cur_pt_offset + amount > cur_page_len)
  319.         num = cur_page_len - cur_pt_offset;
  320.     if (num < 0) num = 0;
  321.  
  322.     cur_gap_end += num;
  323.     cur_page_len -= num;
  324.     if (cur_page == cbuf->last) amount = num;
  325.  
  326.     amount -= num;
  327.     cbuf->is_mod = TRUE;
  328.     cur_is_mod = TRUE;
  329.     if (cur_page_len == 0 &&
  330.          (cur_page->next != NULL || cur_page->prev != NULL)) {
  331.         vpage = cur_page->next;
  332.         tmp = 0;
  333.         if (vpage == NULL) {
  334.             vpage = cur_page->prev;
  335.             tmp = vpage->page_len;
  336.             }
  337.         B_MarkUpdateNP(vpage, tmp);
  338.         B_PageFree(cbuf, cur_page);
  339.         cur_page = NULL;
  340.         }
  341.     else    {
  342.         vpage = cur_page;
  343.         tmp = cur_pt_offset;
  344.         if (tmp >= cur_page_len && cur_page->next) {
  345.             vpage = cur_page->next;
  346.             tmp = 0;
  347.             }
  348.         B_MarkUpdate(vpage, num, tmp);
  349.         }
  350.     B_PageToCurrent(vpage);
  351.     B_MovePointTo(tmp);
  352.     if (amount != 0)
  353.         BCharDelete(amount);
  354.     else    B_SetScreenMarks(TRUE);
  355.     }
  356.  
  357.  
  358. /* ------------------------------------------------------------ */
  359.  
  360. /* Load the buffer with the current file. */
  361.  
  362. FLAG
  363. BFileRead()
  364.     {
  365.     int fd;
  366.     int len;
  367.     struct mark *mptr;
  368. #if defined(UNIX)
  369.     struct stat statbuf;
  370. #endif
  371. #if defined(MSDOS)
  372.     FLAG cr_found = FALSE;
  373. #endif
  374.     FLAG ok = TRUE;
  375.  
  376.     B_PageToCurrent(cbuf->first);
  377.     while (cur_page->next != NULL) B_PageFree(cbuf, cur_page->next);
  378.  
  379.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  380.         if (mptr->pptr && mptr->bptr == cbuf) {
  381.             mptr->pptr = cur_page;
  382.             mptr->mark_offset = 0;
  383.             mptr->is_mod = TRUE;
  384.             }
  385.         }
  386.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  387.         if (mptr->pptr != NULL && mptr->bptr == cbuf) {
  388.             mptr->pptr = cur_page;
  389.             mptr->mark_offset = 0;
  390.             mptr->is_mod = TRUE;
  391.             }
  392.         }
  393.  
  394. #if defined(MSDOS)
  395. #define O_RDONLY    0    /* dummy */
  396. #endif
  397.     if ((fd = open(cbuf->fname, O_RDONLY, 0)) < 0) {
  398.         B_MovePointTo(0);
  399.         cur_gap_start = cur_page_start;
  400.         cur_gap_end = cur_page_start + PAGESIZE;
  401.         cur_page_len = 0;
  402.         cur_is_mod = FALSE;
  403.         cbuf->is_mod = FALSE;
  404.         cur_col = 0;
  405. #if defined(UNIX)
  406.         cbuf->file_time = 0;
  407. #endif
  408.         return(TRUE);
  409.         }
  410.  
  411.     while ((len = read(fd, cur_page_start, PAGESIZE)) > 0) {
  412.         cur_gap_start = cur_page_start + len;
  413.         cur_gap_end = cur_page_start + PAGESIZE;
  414.         cur_page_len = len;
  415.         B_MovePointTo(0);
  416.         cur_is_mod = TRUE;
  417. #if defined(MSDOS)
  418.         if (!isuarg && cr_found && *cur_cptr == LF) {
  419.             *cur_page_start = NL;
  420.             --(cur_page->prev->page_len);
  421.             --(cur_page->prev->gap_start);
  422.             }
  423.         cr_found = FALSE;
  424.         while (cur_pt_offset < cur_page_len) {
  425.             if (!isuarg && *cur_cptr == ZCZ) break;
  426.             if (!isuarg && *cur_cptr == CR) {
  427.                 B_MovePointTo(cur_pt_offset + 1);
  428.                 B_GetGap();
  429.                 if (cur_pt_offset >= cur_page_len)
  430.                     cr_found = TRUE;
  431.                 else if (*cur_cptr == LF) {
  432.                     --cur_gap_start;
  433.                     --cur_page_len;
  434.                     *cur_gap_end = NL;
  435.                     }
  436.                 B_MovePointTo(cur_pt_offset - 1);
  437.                 }
  438.             B_MovePointTo(cur_pt_offset + 1);
  439.             }
  440.         if ((!isuarg && *cur_cptr == ZCZ) || len < PAGESIZE) break;
  441. #else
  442.         B_MovePointTo(cur_page_len);
  443.         if (len < PAGESIZE) break;
  444. #endif
  445.         if (B_PageAllocate(cbuf, cur_page, NULL) == NULL) {
  446.             ok = FALSE;
  447.             break;
  448.             }
  449.         B_PageToCurrent(cur_page->next);
  450.         B_MovePointTo(0);
  451.         }
  452.     if (len < 0) ok = FALSE;
  453. #if defined(UNIX)
  454.     fstat(fd, &statbuf);
  455.     cbuf->file_time = statbuf.st_mtime;
  456. #endif
  457.     close(fd);
  458.     if (cur_pt_offset == 0 && cur_page != cbuf->first) {
  459.         B_PageFree(cbuf, cur_page);
  460.         cur_page = NULL;
  461.         }
  462.     else    {
  463.         B_GetGap();
  464.         cur_gap_end = cur_page_start + PAGESIZE;
  465.         cur_page_len = cur_pt_offset;
  466.         }
  467.     B_PageToCurrent(cbuf->first);
  468.     B_MovePointTo(0);
  469.     cur_col = 0;
  470.     cbuf->is_mod = FALSE;
  471.     if (c.g.wrap_allowed) B_FileReadCheck();
  472.     return(ok);
  473.     }
  474.  
  475.  
  476. /* ------------------------------------------------------------ */
  477.  
  478. /* Write the buffer to its file. */
  479.  
  480. FLAG
  481. BFileWrite()
  482.     {
  483.     struct virt_page *vpage;
  484.     int fd;
  485.     int len;
  486.     FLAG was_err;
  487.     char *cptr;
  488.     char buf[PAGESIZE];
  489. #if defined(MSDOS)
  490.     char chr;
  491.  
  492.     if ((fd = creat(cbuf->fname)) < 0) return(FALSE);
  493. #endif
  494. #if defined(UNIX)
  495.     struct stat statbuf;
  496.  
  497.     if (stat(cbuf->fname, &statbuf) >= 0) {
  498.         if ((cbuf->file_time != 0 &&
  499.              (cbuf->file_time != statbuf.st_mtime)) &&
  500.              !KAsk("Overwrite changed/existing file?"))
  501.             return(FALSE);
  502.         }
  503.     if ((fd = open(cbuf->fname, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
  504.         return(FALSE);
  505. #endif
  506.  
  507.     BMarkToPoint(cwin->point);
  508.     cptr = buf;
  509.     for (vpage = cbuf->first, was_err = FALSE;
  510.          vpage != NULL && !was_err; ) {
  511.         B_PageToCurrent(vpage);
  512.         B_MovePointTo(0);
  513.         vpage = cur_page->next;
  514.         while (cur_pt_offset < cur_page_len) {
  515. #if defined(MSDOS)
  516.             chr = *cur_cptr;
  517.             if (!isuarg && chr == NL) {
  518.                 *cptr++ = CR;
  519.                 if (cptr >= &buf[PAGESIZE]) {
  520.                     was_err = write(fd, buf, PAGESIZE)
  521.                         != PAGESIZE;
  522.                     if (was_err) break;
  523.                     cptr = buf;
  524.                     }
  525.                 chr = LF;
  526.                 }
  527.             *cptr++ = chr;
  528. #else
  529.             *cptr++ = *cur_cptr;
  530. #endif
  531.             if (cptr >= &buf[PAGESIZE]) {
  532.                 was_err = write(fd, buf, PAGESIZE) != PAGESIZE;
  533.                 if (was_err) break;
  534.                 cptr = buf;
  535.                 }
  536.             B_MovePointTo(cur_pt_offset + 1);
  537.             }
  538.         }
  539.     len = cptr - buf;
  540.     if (was_err || len != write(fd, buf, len))
  541.         DError("Error writing file");
  542.     else    cbuf->is_mod = FALSE;
  543. #if defined(UNIX)
  544.     fstat(fd,&statbuf);
  545.     cbuf->file_time = statbuf.st_mtime;
  546. #endif
  547.     close(fd);
  548.     BPointToMark(cwin->point);
  549.     return(TRUE);
  550.     }
  551.  
  552.  
  553. /* ------------------------------------------------------------ */
  554.  
  555. /* Write out one modified page. */
  556.  
  557. void
  558. BFlush()
  559.     {
  560.     struct phys_page *ppage;
  561.  
  562.     for (ppage = last_phys_page; ppage->prev != NULL &&
  563.         (ppage->page_loc != 'S' || !ppage->is_mod);
  564.         ppage = ppage->prev) ;
  565.     if (ppage->prev == NULL) return;
  566.     if (ppage->pptr->page_len != 0) {
  567. #if defined(MSDOS)
  568.         char huge *tmp = (char huge *)((long)swap_base << 16);
  569.         BlockPut(tmp + ((long)ppage->page_num) * PAGESIZE,
  570.             ppage->page_data, PAGESIZE);
  571. #endif
  572. #if defined(UNIX)
  573.         memmove(swap_base + ppage->page_num * PAGESIZE,
  574.             ppage->page_data, PAGESIZE);
  575. #endif
  576.         }
  577.     ppage->is_mod = FALSE;
  578.     }
  579.  
  580.  
  581. /* ------------------------------------------------------------ */
  582.  
  583. /* Return the current character. */
  584.  
  585. char
  586. BGetChar()
  587.     {
  588.     return(*cur_cptr);
  589.     }
  590.  
  591.  
  592. /* ------------------------------------------------------------ */
  593.  
  594. /* Return the current character and move the point by 1 char.  Same as
  595. c = BGetChar(); BMoveBy(1);, but optimized for speed. */
  596.  
  597. char
  598. BGetCharAdv()
  599.     {
  600.     int num;
  601.     char chr = *cur_cptr;
  602.  
  603.     if (cur_pt_offset >= cur_page_len) return(chr);
  604.     if (chr == NL || chr == SNL)
  605.         cur_col = 0;
  606.     else if (cur_col >= 0)
  607.         cur_col += TGetWidth(chr, cur_col);
  608.     if (++cur_pt_offset < cur_page_len) {
  609.         if (++cur_cptr == cur_gap_start) cur_cptr = cur_gap_end;
  610.         return(chr);
  611.         }
  612.     --cur_pt_offset;
  613.  
  614.     num = cur_pt_offset + 1;
  615.     if (num >= 0 && num < cur_page_len) {
  616.         B_MovePointTo(num);
  617.         return(chr);
  618.         }
  619.     if (num >= cur_page_len && cbuf->last == cur_page) {
  620.         B_MovePointTo(cur_page_len);
  621.         return(chr);
  622.         }
  623.     if (num < 0) {
  624.         if (cur_page == cbuf->first) {
  625.             B_MovePointTo(0);
  626.             return(chr);
  627.             }
  628.         B_PageToCurrent(cur_page->prev);
  629.         B_MovePointTo(cur_page_len);
  630.         }
  631.     else    {
  632.         num -= cur_page_len;    /* must use this cur_page_len */
  633.         B_PageToCurrent(cur_page->next);
  634.         B_MovePointTo(0);
  635.         }
  636.     if (num != 0) BMoveBy(num);
  637.     return(chr);
  638.     }
  639.  
  640.  
  641. /* ------------------------------------------------------------ */
  642.  
  643. /* Return the current column. */
  644.  
  645. int
  646. BGetCol()
  647.     {
  648.  
  649.     if (cur_col >= 0) return(cur_col);
  650.     if (cbuf->num_pages == 1 && cbuf->first->page_len == 0) {
  651.         cur_col = 0;
  652.         return(0);
  653.         }
  654.     BMarkToPoint(getmark);
  655.     if (BSearchB(NL, SNL)) BMoveBy(1);
  656.     cur_col = 0;
  657.     while (BIsBeforeMark(getmark)) BMoveBy(1);
  658.     return(cur_col);
  659.     }
  660.  
  661.  
  662. /* ------------------------------------------------------------ */
  663.  
  664. /* Returns the buffer's length. */
  665.  
  666. long
  667. BGetLength(bptr)
  668.     struct buffer *bptr;
  669.     {
  670.     long len;
  671.     struct virt_page *vpage;
  672.  
  673.     len = 0;
  674.     for (vpage = bptr->first; vpage != NULL; vpage = vpage->next) {
  675.         if (vpage == cur_page)
  676.             len += cur_page_len;
  677.         else    len += vpage->page_len;
  678.         }
  679.     return(len);
  680.     }
  681.  
  682.  
  683. /* ------------------------------------------------------------ */
  684.  
  685. /* Return the current point location. */
  686.  
  687. long
  688. BGetLocation()
  689.     {
  690.     long len;
  691.     struct virt_page *vpage;
  692.  
  693.     len = 0;
  694.     for (vpage = cbuf->first; vpage != cur_page; vpage = vpage->next)
  695.         len += vpage->page_len;
  696.     return(len + cur_pt_offset);
  697.     }
  698.  
  699.  
  700. /* ------------------------------------------------------------ */
  701.  
  702. /* Insert the specified character into the buffer. Return True on
  703. success or False on buffer full. */
  704.  
  705. FLAG
  706. BInsChar(chr)
  707.     char chr;
  708.     {
  709.     FLAG ok;
  710.  
  711.     ok = B_InsChar(chr);
  712.     B_SetScreenMarks(FALSE);
  713.     return(ok);
  714.     }
  715.  
  716.  
  717. /* ------------------------------------------------------------ */
  718.  
  719. /* Insert AMT spaces. */
  720.  
  721. void
  722. BInsSpaces(amt)
  723.     int amt;
  724.     {
  725.     while (amt-- > 0) B_InsChar(SP);
  726.     B_SetScreenMarks(FALSE);
  727.     }
  728.  
  729.  
  730. /* ------------------------------------------------------------ */
  731.  
  732. /* Insert the string into the buffer. Return True on success or False
  733. on buffer full. */
  734.  
  735. FLAG
  736. BInsStr(str)
  737.     char *str;
  738.     {
  739.     FLAG ok = TRUE;
  740.  
  741.     while (*str != NUL) {
  742.         if (!B_InsChar(*str++)) {
  743.             ok = FALSE;
  744.             break;
  745.             }
  746.         }
  747.     B_SetScreenMarks(FALSE);
  748.     return(ok);
  749.     }
  750.  
  751.  
  752. /* ------------------------------------------------------------ */
  753.  
  754. /* Put in the right number of tabs and spaces */
  755.  
  756. void
  757. BInsTabSpaces(amt)
  758.     int amt;
  759.     {
  760.     for ( ; amt >= cbuf->c.tab_spacing; amt -= cbuf->c.tab_spacing) {
  761.         B_InsChar(TAB);
  762.         }
  763.     BInsSpaces(amt);
  764.     }
  765.  
  766.  
  767. /* ------------------------------------------------------------ */
  768.  
  769. /* Put the point in a special, repeatable invalid state off the end of
  770. the buffer. */
  771.  
  772. void
  773. BInvalid()
  774.     {
  775.     B_PageToCurrent(cbuf->last);
  776.     B_MovePointTo(cur_page_len + 1);
  777.     cur_col = -1;
  778.     }
  779.  
  780.  
  781. /* ------------------------------------------------------------ */
  782.  
  783. /* Is the point after the mark? */
  784.  
  785. FLAG
  786. BIsAfterMark(mptr)
  787.     struct mark *mptr;
  788.     {
  789.     struct virt_page *vpage;
  790.  
  791.     if (mptr->pptr == NULL || mptr->bptr != cbuf) {
  792.         DError("Bad mark");
  793.         return(FALSE);
  794.         }
  795.     if (mptr->pptr == cur_page) return(cur_pt_offset > mptr->mark_offset);
  796.     for (vpage = cur_page; vpage && vpage != mptr->pptr;
  797.         vpage = vpage->prev);
  798.     return(vpage != NULL);
  799.     }
  800.  
  801.  
  802. /* ------------------------------------------------------------ */
  803.  
  804. /* Is the point at the mark? */
  805.  
  806. FLAG
  807. BIsAtMark(mptr)
  808.     struct mark *mptr;
  809.     {
  810.     return(mptr->pptr == cur_page && mptr->mark_offset == cur_pt_offset);
  811.     }
  812.  
  813.  
  814. /* ------------------------------------------------------------ */
  815.  
  816. /* Is the point before the mark? */
  817.  
  818. FLAG
  819. BIsBeforeMark(mptr)
  820.     struct mark *mptr;
  821.     {
  822.     struct virt_page *vpage;
  823.  
  824.     if (mptr->pptr == NULL || mptr->bptr != cbuf) {
  825.         DError("Bad mark");
  826.         return(FALSE);
  827.         }
  828.     if (mptr->pptr == cur_page) return(cur_pt_offset < mptr->mark_offset);
  829.     for (vpage = cur_page; vpage != NULL && vpage != mptr->pptr;
  830.         vpage = vpage->next);
  831.     return(vpage != NULL);
  832.     }
  833.  
  834.  
  835. /* ------------------------------------------------------------ */
  836.  
  837. /* Is the point at the end of the buffer? */
  838.  
  839. FLAG
  840. BIsEnd()
  841.     {
  842.     return(cur_pt_offset >= cur_page_len && cur_page == cbuf->last);
  843.     }
  844.  
  845.  
  846. /* ------------------------------------------------------------ */
  847.  
  848. /* Return True if the buffer is free, or False if it is in use. */
  849.  
  850. FLAG
  851. BIsFree(bptr)
  852.     struct buffer *bptr;
  853.     {
  854.     return(bptr->num_pages == 0);
  855.     }
  856.  
  857.  
  858. /* ------------------------------------------------------------ */
  859.  
  860. /* Has the buffer been modified? */
  861.  
  862. FLAG
  863. BIsMod(bptr)
  864.     struct buffer *bptr;
  865.     {
  866.     return(bptr->is_mod);
  867.     }
  868.  
  869.  
  870. /* ------------------------------------------------------------ */
  871.  
  872. /* Is the point at the beginning of the buffer? */
  873.  
  874. FLAG
  875. BIsStart()
  876.     {
  877.     return(cur_pt_offset == 0 && cur_page == cbuf->first);
  878.     }
  879.  
  880.  
  881. /* ------------------------------------------------------------ */
  882.  
  883. /* Put the cursor in specific column, rounding. */
  884.  
  885. void
  886. BMakeColB(col)
  887.     int col;
  888.     {
  889.     int old_col;
  890.  
  891.     if (BSearchB(NL, SNL)) BMoveBy(1);
  892.     cur_col = 0;
  893.     while (cur_col < col && *cur_cptr != NL && *cur_cptr != SNL &&
  894.          !BIsEnd()) {
  895.         old_col = cur_col;
  896.         BMoveBy(1);
  897.         }
  898.     if (cur_col != 0 && cur_col - col > col - old_col) BMoveBy(-1);
  899.     }
  900.  
  901.  
  902. /* ------------------------------------------------------------ */
  903.  
  904. /* Put cursor in specific column, no rounding. */
  905.  
  906. void
  907. BMakeColF(col)
  908.     int col;
  909.     {
  910.     if (BSearchB(NL, SNL)) BMoveBy(1);
  911.     cur_col = 0;
  912.     while (cur_col < col && *cur_cptr != NL && *cur_cptr != SNL &&
  913.          !BIsEnd()) {
  914.         BMoveBy(1);
  915.         }
  916.     }
  917.  
  918.  
  919. /* ------------------------------------------------------------ */
  920.  
  921. /* Return the mark's buffer. */
  922.  
  923. struct buffer *
  924. BMarkBuf(mptr)
  925.     struct mark *mptr;
  926.     {
  927.     return(mptr->bptr);
  928.     }
  929.  
  930.  
  931. /* ------------------------------------------------------------ */
  932.  
  933. /* Create a mark at the point. */
  934.  
  935. struct mark *
  936. BMarkCreate()
  937.     {
  938.     struct mark *mptr;
  939.  
  940.     for (mptr = marks; mptr < &marks[MAXMARK] && mptr->pptr != NULL;
  941.         mptr++) ;
  942.     if (mptr >= &marks[MAXMARK - 1]) {
  943.         DError("Out of marks");
  944.         mptr = &marks[MAXMARK - 1];
  945.         }
  946.     mptr->bptr = cbuf;
  947.     mptr->pptr = cur_page;
  948.     mptr->mark_offset = cur_pt_offset;
  949.     return(mptr);
  950.     }
  951.  
  952.  
  953. /* ------------------------------------------------------------ */
  954.  
  955. /* Free the supplied mark. */
  956.  
  957. void
  958. BMarkDelete(mptr)
  959.     struct mark *mptr;
  960.     {
  961.     mptr->pptr = NULL;
  962.     }
  963.  
  964.  
  965. /* ------------------------------------------------------------ */
  966.  
  967. /* Test and clear the modified flag on the specified screen mark. */
  968.  
  969. FLAG
  970. BMarkIsMod(mptr)
  971.     struct mark *mptr;
  972.     {
  973.     FLAG is_mod;
  974.  
  975.     is_mod = mptr->is_mod;
  976.     mptr->is_mod = FALSE;
  977.     return(mptr->bptr != cbuf || is_mod);
  978.     }
  979.  
  980.  
  981. /* ------------------------------------------------------------ */
  982.  
  983. /* Set the modified flag on the specified screen mark. */
  984.  
  985. void
  986. BMarkSetMod(mptr)
  987.     struct mark *mptr;
  988.     {
  989.     mptr->is_mod = TRUE;
  990.     }
  991.  
  992.  
  993. /* ------------------------------------------------------------ */
  994.  
  995. /* Return the mark for the specifed row. */
  996.  
  997. struct mark *
  998. BMarkScreen(row)
  999.     int row;
  1000.     {
  1001.     return(&screenmarks[row]);
  1002.     }
  1003.  
  1004.  
  1005. /* ------------------------------------------------------------ */
  1006.  
  1007. /* Swap the point and the mark. */
  1008.  
  1009. void
  1010. BMarkSwap(mptr)
  1011.     struct mark *mptr;
  1012.     {
  1013.     struct mark tmp;
  1014.  
  1015.     tmp = *mptr;
  1016.     BMarkToPoint(mptr);
  1017.     BPointToMark(&tmp);
  1018.     }
  1019.  
  1020.  
  1021. /* ------------------------------------------------------------ */
  1022.  
  1023. /* Put the mark where the point is. */
  1024.  
  1025. void
  1026. BMarkToPoint(mptr)
  1027.     struct mark *mptr;
  1028.     {
  1029.     mptr->bptr = cbuf;
  1030.     mptr->pptr = cur_page;
  1031.     mptr->mark_offset = cur_pt_offset;
  1032.     }
  1033.  
  1034.  
  1035. /* ------------------------------------------------------------ */
  1036.  
  1037. /* Move the point relative to its current position by AMT characters.
  1038. */
  1039.  
  1040. void
  1041. BMoveBy(amt)
  1042.     int amt;
  1043.     {
  1044.     int num;
  1045.  
  1046.     if (amt == 1) {
  1047.         if (cur_pt_offset >= cur_page_len) return;
  1048.         if (*cur_cptr == NL || *cur_cptr == SNL)
  1049.             cur_col = 0;
  1050.         else if (cur_col >= 0)
  1051.             cur_col += TGetWidth(*cur_cptr, cur_col);
  1052.         if (++cur_pt_offset < cur_page_len) {
  1053.             if (++cur_cptr == cur_gap_start)
  1054.                 cur_cptr = cur_gap_end;
  1055.             return;
  1056.             }
  1057.         --cur_pt_offset;
  1058.         }
  1059.     else    cur_col = -1;
  1060.  
  1061.     num = cur_pt_offset + amt;
  1062.     if (num >= 0 && num < cur_page_len) {
  1063.         B_MovePointTo(num);
  1064.         return;
  1065.         }
  1066.     if (num >= cur_page_len && cbuf->last == cur_page) {
  1067.         B_MovePointTo(cur_page_len);
  1068.         return;
  1069.         }
  1070.     if (num < 0) {
  1071.         if (cur_page == cbuf->first) {
  1072.             B_MovePointTo(0);
  1073.             return;
  1074.             }
  1075.         B_PageToCurrent(cur_page->prev);
  1076.         B_MovePointTo(cur_page_len);
  1077.         }
  1078.     else    {
  1079.         num -= cur_page_len;    /* must use this cur_page_len */
  1080.         B_PageToCurrent(cur_page->next);
  1081.         B_MovePointTo(0);
  1082.         }
  1083.  
  1084.     if (num != 0) BMoveBy(num);
  1085.     }
  1086.  
  1087.  
  1088. /* ------------------------------------------------------------ */
  1089.  
  1090. /* Set the point to the end of the buffer. */
  1091.  
  1092. void
  1093. BMoveToEnd()
  1094.     {
  1095.     B_PageToCurrent(cbuf->last);
  1096.     B_MovePointTo(cur_page_len);
  1097.     cur_col = -1;
  1098.     }
  1099.  
  1100.  
  1101. /* ------------------------------------------------------------ */
  1102.  
  1103. /* Set the point to the start of the buffer. */
  1104.  
  1105. void
  1106. BMoveToStart()
  1107.     {
  1108.     B_PageToCurrent(cbuf->first);
  1109.     B_MovePointTo(0);
  1110.     cur_col = 0;
  1111.     }
  1112.  
  1113.  
  1114. /* ------------------------------------------------------------ */
  1115.  
  1116. /* Move the point to the specified mark. */
  1117.  
  1118. void
  1119. BPointToMark(mptr)
  1120.     struct mark *mptr;
  1121.     {
  1122.     if (mptr->pptr == NULL) {
  1123.         DError("Not a mark");
  1124.         return;
  1125.         }
  1126.     if (mptr->bptr != cbuf) BBufGoto(mptr->bptr);
  1127.     B_PageToCurrent(mptr->pptr);
  1128.     B_MovePointTo(mptr->mark_offset);
  1129.     cur_col = -1;
  1130.     }
  1131.  
  1132.  
  1133. /* ------------------------------------------------------------ */
  1134.  
  1135. /* Restore the current column. */
  1136.  
  1137. void
  1138. BPopState()
  1139.     {
  1140.     cur_col = savecol;
  1141.     }
  1142.  
  1143.  
  1144. /* ------------------------------------------------------------ */
  1145.  
  1146. /* Save the current column. */
  1147.  
  1148. void
  1149. BPushState()
  1150.     {
  1151.     savecol = cur_col;
  1152.     }
  1153.  
  1154.  
  1155. /* ------------------------------------------------------------ */
  1156.  
  1157. /* Copy the region from the current point to mark MPTR to the buffer
  1158. specified by BPTR. */
  1159.  
  1160. void
  1161. BRegCopy(mptr, bptr)
  1162.     struct mark *mptr;
  1163.     struct buffer *bptr;
  1164.     {
  1165.     struct buffer *save_buf = cbuf;
  1166.     struct mark *mptr2;
  1167.     struct mark *mptr3;
  1168.     FLAG isafter;
  1169.     int from;
  1170.     int to;
  1171.     char *save_point;
  1172.  
  1173.     if (bptr == cbuf) {
  1174.         DError("Must copy to a different buffer");
  1175.         return;
  1176.         }
  1177.     if (isafter = BIsAfterMark(mptr)) BMarkSwap(mptr);
  1178.     mptr2 = BMarkCreate();
  1179.     while (BIsBeforeMark(mptr)) {
  1180.         if (cur_page == mptr->pptr)
  1181.             from = mptr->mark_offset - cur_pt_offset;
  1182.         else    from = cur_page_len - cur_pt_offset;
  1183.         B_GetGap();
  1184.         cur_is_mod = TRUE;
  1185.         save_point = cur_gap_end;
  1186.  
  1187.         BBufGoto(bptr);
  1188.         to = PAGESIZE - cur_page_len;
  1189.         if (to == 0)
  1190.             if (B_PageSplit(cur_pt_offset +
  1191.                  ((cur_pt_offset < PAGESIZE / 2) ? 1 : -1)))
  1192.                 to = PAGESIZE - cur_page_len;
  1193.             else     {
  1194.                 BBufGoto(save_buf);
  1195.                 break;
  1196.                 }
  1197.         B_GetGap();
  1198.         if (from < to) to = from;
  1199.         memmove(cur_gap_start, save_point, to);
  1200.         cur_page_len += to;
  1201.         cur_gap_start += to;
  1202.         for (mptr3 = marks; mptr3 < &marks[MAXMARK]; ++mptr3) {
  1203.             if (mptr3->pptr == cur_page &&
  1204.                  mptr3->mark_offset > cur_pt_offset) {
  1205.                 mptr3->mark_offset += to;
  1206.                 }
  1207.             }
  1208.         for (mptr3 = screenmarks; mptr3 < &screenmarks[MAXSMARK];
  1209.              ++mptr3) {
  1210.             if (mptr3->pptr == cur_page &&
  1211.                  mptr3->mark_offset > cur_pt_offset) {
  1212.                 mptr3->mark_offset += to;
  1213.                 }
  1214.             }
  1215.         B_MovePointTo(cur_pt_offset + to);
  1216.         B_SetScreenMarks(FALSE);
  1217.         cur_is_mod = TRUE;
  1218.         cbuf->is_mod = TRUE;
  1219.         BBufGoto(save_buf);
  1220.         BMoveBy(to);
  1221.         }
  1222.     BPointToMark(mptr2);
  1223.     BMarkDelete(mptr2);
  1224.     if (isafter) BMarkSwap(mptr);
  1225.     }
  1226.  
  1227.  
  1228. /* ------------------------------------------------------------ */
  1229.  
  1230. /* delete from the point to the mark */
  1231.  
  1232. void
  1233. BRegDelete(mptr)
  1234.     struct mark *mptr;
  1235.     {
  1236.     if (BIsAfterMark(mptr)) BMarkSwap(mptr);
  1237.     if (!BIsBeforeMark(mptr)) return;
  1238.  
  1239.     if (cur_page == mptr->pptr)
  1240.         BCharDelete(mptr->mark_offset - cur_pt_offset);
  1241.     else    {
  1242.         BCharDelete(cur_page_len - cur_pt_offset);
  1243.         BRegDelete(mptr);
  1244.         }
  1245.     }
  1246.  
  1247.  
  1248. /* ------------------------------------------------------------ */
  1249.  
  1250. /* Search backwards for both C1 and C2. */
  1251.  
  1252. FLAG
  1253. BSearchB(c1, c2)
  1254.     char c1;
  1255.     char c2;
  1256.     {
  1257.     char *cptr;
  1258.  
  1259.     do    {
  1260.         if (BIsStart()) return(FALSE);
  1261.         if (BIsEnd() || cur_cptr == cur_gap_end ||
  1262.              cur_cptr == cur_page_start)
  1263.             BMoveBy(-1);
  1264.         else    {
  1265.             cptr = (cur_cptr >= cur_gap_end) ? cur_gap_end :
  1266.                 cur_page_start;
  1267.             BMoveBy(max(
  1268.                 B_IndexB(cur_cptr - 1, cur_cptr - cptr, c1),
  1269.                 B_IndexB(cur_cptr - 1, cur_cptr - cptr, c2))
  1270.                     - 1);
  1271.             }
  1272.         } while (*cur_cptr != c1 && *cur_cptr != c2);
  1273.     return(TRUE);
  1274.     }
  1275.  
  1276.  
  1277. /* ------------------------------------------------------------ */
  1278.  
  1279. /* Search forward for both C1 and C2. */
  1280.  
  1281. FLAG
  1282. BSearchF(c1, c2)
  1283.     char c1;
  1284.     char c2;
  1285.     {
  1286.     while (!BIsEnd() && *cur_cptr != c1 && *cur_cptr != c2) {
  1287.         if (cur_cptr >= cur_gap_start) {
  1288.             B_MovePointTo(cur_pt_offset + min(
  1289. B_IndexF(cur_cptr, (cur_page_start + PAGESIZE) - cur_cptr, c1),
  1290. B_IndexF(cur_cptr, (cur_page_start + PAGESIZE) - cur_cptr, c2)));
  1291.             }
  1292.         else    {
  1293.             B_MovePointTo(cur_pt_offset + min(
  1294. B_IndexF(cur_cptr, cur_gap_start - cur_cptr, c1),
  1295. B_IndexF(cur_cptr, cur_gap_start - cur_cptr, c2)));
  1296.             }
  1297.         if (cur_pt_offset >= cur_page_len && cur_page->next) {
  1298.             B_PageToCurrent(cur_page->next);
  1299.             B_MovePointTo(0);
  1300.             }
  1301.         }
  1302.     cur_col = -1;
  1303.     if (!BIsEnd()) {
  1304.         BMoveBy(1);
  1305.         return(TRUE);
  1306.         }
  1307.     else    return(FALSE);
  1308.     }
  1309.  
  1310.  
  1311. /* ------------------------------------------------------------ */
  1312.  
  1313. /* The buffer has just been read in.  Check it for a ruler line. */
  1314.  
  1315. void
  1316. B_FileReadCheck()
  1317.     {
  1318.     if (IsNL()) BMoveBy(1);
  1319.     for (;;) {
  1320.         if (*cur_cptr == SP || *cur_cptr == TAB) {
  1321.             MovePastF(IsWhite);
  1322.             if (!IsNL()) break;
  1323.             BMoveBy(1);
  1324.             }
  1325.         else if (*cur_cptr == '.' || *cur_cptr == '@') {
  1326.             SearchNLF();
  1327.             }
  1328.         else if (*cur_cptr == ZCK) {
  1329.             B_RulerLine();
  1330.             break;
  1331.             }
  1332.         else break;
  1333.         }
  1334.     BMoveToStart();
  1335.     }
  1336.  
  1337.  
  1338. /* ------------------------------------------------------------ */
  1339.  
  1340. /* Move the gap to the point. */
  1341.  
  1342. void
  1343. B_GetGap()
  1344.     {
  1345.     if (cur_cptr == cur_gap_end) return;
  1346.  
  1347.     if (cur_cptr < cur_gap_start) {
  1348.         cur_gap_end -= cur_gap_start - cur_cptr;
  1349.         memmove(cur_gap_end, cur_cptr, cur_gap_start - cur_cptr);
  1350.         cur_gap_start = cur_cptr;
  1351.         cur_cptr = cur_gap_end;
  1352.         }
  1353.     else    {
  1354.         memmove(cur_gap_start, cur_gap_end, cur_cptr - cur_gap_end);
  1355.         cur_gap_start += cur_cptr - cur_gap_end;
  1356.         cur_gap_end = cur_cptr;
  1357.         }
  1358.     }
  1359.  
  1360.  
  1361. /* ------------------------------------------------------------ */
  1362.  
  1363. /* Return the offset of CHR backwards in BUF, which is LEN characters
  1364. long. */
  1365.  
  1366. int
  1367. B_IndexB(buf, len, chr)
  1368.     char *buf;
  1369.     int len;
  1370.     char chr;
  1371.     {
  1372.     char *cptr;
  1373.  
  1374.     for (cptr = buf; len-- > 0 && *cptr != chr; --cptr) ;
  1375.     return(cptr - buf);
  1376.     }
  1377.  
  1378.  
  1379. /* ------------------------------------------------------------ */
  1380.  
  1381. /* Return the offset of CHR in BUF, which is LEN characters long. */
  1382.  
  1383. int
  1384. B_IndexF(buf, len, chr)
  1385.     char *buf;
  1386.     int len;
  1387.     char chr;
  1388.     {
  1389.     char *cptr;
  1390.  
  1391.     for (cptr = buf; len-- > 0 && *cptr != chr; ++cptr) ;
  1392.     return(cptr - buf);
  1393.     }
  1394.  
  1395.  
  1396. /* ------------------------------------------------------------ */
  1397.  
  1398. /* Insert the specified character into the buffer. */
  1399.  
  1400. FLAG
  1401. B_InsChar(chr)
  1402.     char chr;
  1403.     {
  1404.     struct mark *mptr;
  1405.  
  1406.     if (cur_gap_start == cur_gap_end && !B_PageSplit(PAGESIZE / 2))
  1407.         return(FALSE);
  1408.     B_GetGap();                
  1409.     *cur_gap_start++ = chr;
  1410.     ++cur_page_len;
  1411.     B_MovePointTo(cur_pt_offset + 1);
  1412.  
  1413.     if (chr == NL || chr == SNL)
  1414.         cur_col = 0;
  1415.     else if (cur_col >= 0)
  1416.         cur_col += TGetWidth(chr, cur_col);
  1417.  
  1418.     cbuf->is_mod = TRUE;
  1419.     cur_is_mod = TRUE;
  1420.  
  1421.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1422.         if (mptr->pptr == cur_page &&
  1423.              mptr->mark_offset >= cur_pt_offset) {
  1424.             ++(mptr->mark_offset);
  1425.             }
  1426.         }
  1427.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1428.         if (mptr->pptr == cur_page &&
  1429.              mptr->mark_offset >= cur_pt_offset) {
  1430.             ++(mptr->mark_offset);
  1431.             }
  1432.         }
  1433.     return(TRUE);
  1434.     }
  1435.  
  1436.  
  1437. /* ------------------------------------------------------------ */
  1438.  
  1439. /* Update the marks to a new page using NEW_PAGE, AMT, NEW_OFFSET. */
  1440.  
  1441. void
  1442. B_MarkUpdate(new_page, amt, new_offset)
  1443.     struct virt_page *new_page;
  1444.     int amt;
  1445.     int new_offset;
  1446.     {
  1447.     struct mark *mptr;
  1448.  
  1449.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1450.         if (mptr->pptr == cur_page &&
  1451.              mptr->mark_offset >= cur_pt_offset) {
  1452.             if (mptr->mark_offset >= cur_pt_offset + amt)
  1453.                 mptr->mark_offset -= amt;
  1454.             else    {
  1455.                 mptr->pptr = new_page;
  1456.                 mptr->mark_offset = new_offset;
  1457.                 }
  1458.             }
  1459.         }
  1460.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1461.         if (mptr->pptr == cur_page &&
  1462.              mptr->mark_offset >= cur_pt_offset) {
  1463.             if (mptr->mark_offset >= cur_pt_offset + amt)
  1464.                 mptr->mark_offset -= amt;
  1465.             else    {
  1466.                 mptr->pptr = new_page;
  1467.                 mptr->mark_offset = new_offset;
  1468.                 }
  1469.             }
  1470.         }
  1471.     }
  1472.  
  1473.  
  1474. /* ------------------------------------------------------------ */
  1475.  
  1476. /* Update the marks to a new page using NEW_PAGE, NEW_OFFSET. */
  1477.  
  1478. void
  1479. B_MarkUpdateNP(new_page, new_offset)
  1480.     struct virt_page *new_page;
  1481.     int new_offset;
  1482.     {
  1483.     struct mark *mptr;
  1484.  
  1485.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1486.         if (mptr->pptr == cur_page) {
  1487.             mptr->pptr = new_page;
  1488.             mptr->mark_offset = new_offset;
  1489.             }
  1490.         }
  1491.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1492.         if (mptr->pptr == cur_page) {
  1493.             mptr->pptr = new_page;
  1494.             mptr->mark_offset = new_offset;
  1495.             }
  1496.         }
  1497.     }
  1498.  
  1499.  
  1500. /* ------------------------------------------------------------ */
  1501.  
  1502. /* Move the point AMT chars into the current page. */
  1503.  
  1504. void
  1505. B_MovePointTo(amt)
  1506.     int amt;
  1507.     {
  1508.     cur_pt_offset = amt;
  1509.     cur_cptr = cur_page_start + amt;
  1510.     if (cur_cptr >= cur_gap_start) cur_cptr += cur_gap_end - cur_gap_start;
  1511.     }
  1512.  
  1513.  
  1514. /* ------------------------------------------------------------ */
  1515.  
  1516. /* Allocate a new page. */
  1517.  
  1518. struct virt_page *
  1519. B_PageAllocate(bptr, prev, next)
  1520.     struct buffer *bptr;
  1521.     struct virt_page *prev;
  1522.     struct virt_page *next;
  1523.     {
  1524.     int cnt;
  1525.     struct virt_page *vpage;
  1526.     struct phys_page *ppage;
  1527.  
  1528.     for (cnt = 0; cnt < num_swap && swap_map[cnt]; ++cnt) ;
  1529.     if (cnt >= num_swap) {
  1530.         DError("Out of swap space");
  1531.         return(NULL);
  1532.         }
  1533.     swap_map[cnt] = TRUE;
  1534.     vpage = &vp[cnt];
  1535.  
  1536.     vpage->next = next;
  1537.     vpage->prev = prev;
  1538.     if (next != NULL)
  1539.         next->prev = vpage;
  1540.     else    bptr->last = vpage;
  1541.     if (prev != NULL)
  1542.         prev->next = vpage;
  1543.     else    bptr->first = vpage;
  1544.  
  1545.     vpage->gap_start = 0;
  1546.     vpage->page_len = 0;
  1547.     vpage->where = 'S';
  1548.     vpage->page_num = cnt;
  1549.     ++(bptr->num_pages);
  1550.     return(vpage);
  1551.     }
  1552.  
  1553.  
  1554. /* ------------------------------------------------------------ */
  1555.  
  1556. /* Find a free page. */
  1557.  
  1558. struct phys_page *
  1559. B_PageFindFree()
  1560.     {
  1561.     struct phys_page *ppage;
  1562.     int cnt;
  1563.  
  1564.     cnt = NUM_PHYS_PAGES / 3 + 1;
  1565.     for (ppage = last_phys_page; --cnt > 0 &&
  1566.          (ppage->page_loc == 'L' || ppage->is_mod);
  1567.          ppage = ppage->prev) ;
  1568.  
  1569.     if (cnt <= 0) {
  1570.         BFlush();
  1571.         for (ppage = last_phys_page; ppage != NULL &&
  1572.              (ppage->page_loc == 'L' || ppage->is_mod);
  1573.              ppage = ppage->prev) ;
  1574.         if (ppage == NULL) {
  1575.             DError("Internal paging error");
  1576.             return(NULL);
  1577.             }
  1578.         }
  1579.  
  1580.     if (ppage->page_loc == 'S') {
  1581.         ppage->pptr->where = 'S';
  1582.         ppage->pptr->page_num = ppage->page_num;
  1583.         }
  1584.     return(ppage);
  1585.     }
  1586.  
  1587.  
  1588. /* ------------------------------------------------------------ */
  1589.  
  1590. /* Free the specifed page. */
  1591.  
  1592. void
  1593. B_PageFree(bptr, vpage)
  1594.     struct buffer *bptr;
  1595.     struct virt_page *vpage;
  1596.     {
  1597.     struct phys_page *ppage;
  1598.  
  1599.     if (vpage->next != NULL)
  1600.         vpage->next->prev = vpage->prev;
  1601.     else    bptr->last = vpage->prev;
  1602.     if (vpage->prev != NULL)
  1603.         vpage->prev->next = vpage->next;
  1604.     else    bptr->first = vpage->next;
  1605.  
  1606.     --(bptr->num_pages);
  1607.  
  1608.     if (vpage->where == 'M') {
  1609.         ppage = &pages[vpage->page_num];
  1610.         swap_map[ppage->page_num] = FALSE;
  1611.         pages[vpage->page_num].page_loc = 'M';
  1612.         pages[vpage->page_num].is_mod = FALSE;
  1613.         }
  1614.     else    swap_map[vpage->page_num] = FALSE;
  1615.     }
  1616.  
  1617.  
  1618. /* ------------------------------------------------------------ */
  1619.  
  1620. /* Split the curent (presumably full) page.  AMOUNT is where to split
  1621. it. */
  1622.  
  1623. FLAG
  1624. B_PageSplit(amount)
  1625.     int amount;
  1626.     {
  1627.     struct mark *mptr;
  1628.     struct virt_page *vpage;
  1629.     struct phys_page *ppage;
  1630.  
  1631.     if ((vpage = B_PageAllocate(cbuf, cur_page, cur_page->next)) == NULL)
  1632.         return(FALSE);
  1633.     B_PageToMemory(vpage);
  1634.  
  1635.     ppage = &pages[vpage->page_num];
  1636.     memmove(ppage->page_data, cur_page_start + amount, PAGESIZE - amount);
  1637.  
  1638.     ppage->is_mod = TRUE;
  1639.     cur_is_mod = TRUE;
  1640.     cur_gap_start = cur_page_start + amount;
  1641.     cur_gap_end = cur_page_start + PAGESIZE;
  1642.     cur_page_len = amount;
  1643.     vpage->page_len = PAGESIZE - amount;
  1644.     vpage->gap_start = PAGESIZE - amount;
  1645.  
  1646.     for (mptr = marks; mptr < &marks[MAXMARK]; ++mptr) {
  1647.         if (mptr->pptr == cur_page && mptr->mark_offset >= amount) {
  1648.             mptr->pptr = vpage;
  1649.             mptr->mark_offset -= amount;
  1650.             }
  1651.         }
  1652.     for (mptr = screenmarks; mptr < &screenmarks[MAXSMARK]; ++mptr) {
  1653.         if (mptr->pptr == cur_page && mptr->mark_offset >= amount) {
  1654.             mptr->pptr = vpage;
  1655.             mptr->mark_offset -= amount;
  1656.             }
  1657.         }
  1658.  
  1659.     if (cur_pt_offset >= amount) {
  1660.         B_PageToCurrent(vpage);
  1661.         B_MovePointTo(cur_pt_offset - amount);
  1662.         }
  1663.     return(TRUE);
  1664.     }
  1665.  
  1666.  
  1667. /* ------------------------------------------------------------ */
  1668.  
  1669. /* Make VPAGE the current page. */
  1670.  
  1671. void
  1672. B_PageToCurrent(vpage)
  1673.     struct virt_page *vpage;
  1674.     {
  1675.     struct phys_page *ppage;
  1676.  
  1677.     if (vpage == NULL) {
  1678.         DError("Null page");
  1679.         return;
  1680.         }
  1681.  
  1682.     if (cur_page == vpage) return;
  1683.  
  1684.     if (cur_page != NULL) {
  1685.         cur_page->page_len = cur_page_len;
  1686.         cur_page->gap_start = cur_gap_start - cur_page_start;
  1687.         pages[cur_page->page_num].is_mod = cur_is_mod;
  1688.         }
  1689.  
  1690.     B_PageToMemory(vpage);
  1691.     cur_page = vpage;
  1692.     ppage = &pages[cur_page->page_num];
  1693.     cur_page_start = ppage->page_data;
  1694.     cur_is_mod = ppage->is_mod;
  1695.     cur_page_len = cur_page->page_len;
  1696.     cur_gap_start = cur_page_start + cur_page->gap_start;
  1697.     cur_gap_end = cur_gap_start - cur_page_len + PAGESIZE;
  1698.  
  1699.     if (ppage == first_phys_page) return;
  1700.     if (ppage->next == NULL)
  1701.         last_phys_page = ppage->prev;
  1702.     else    ppage->next->prev = ppage->prev;
  1703.     if (ppage->prev != NULL) ppage->prev->next = ppage->next;
  1704.     ppage->prev = NULL;
  1705.     ppage->next = first_phys_page;
  1706.     first_phys_page->prev = ppage;
  1707.     first_phys_page = ppage;
  1708.     }
  1709.  
  1710.  
  1711. /* ------------------------------------------------------------ */
  1712.  
  1713. /* Make sure that the specified page is swapped into memory. */
  1714.  
  1715. void
  1716. B_PageToMemory(vpage)
  1717.     struct virt_page *vpage;
  1718.     {
  1719.     struct phys_page *ppage;
  1720.  
  1721.     if (vpage->where == 'M') return;
  1722.     ppage = B_PageFindFree();
  1723.     ppage->page_loc = 'S';
  1724.     ppage->page_num = vpage->page_num;
  1725.     ppage->is_mod = FALSE;
  1726.     ppage->pptr = vpage;
  1727.  
  1728.     if (vpage->page_len != 0) {
  1729. #if defined(MSDOS)
  1730.         char huge *tmp = (char huge *)((long)swap_base << 16);
  1731.         BlockGet(ppage->page_data,
  1732.             tmp + ((long)ppage->page_num) * PAGESIZE, PAGESIZE);
  1733. #endif
  1734. #if defined(UNIX)
  1735.         memmove(ppage->page_data,
  1736.             swap_base + ppage->page_num * PAGESIZE, PAGESIZE);
  1737. #endif
  1738.         }
  1739.  
  1740.     vpage->where = 'M';
  1741.     vpage->page_num = ppage - pages;
  1742.     }
  1743.  
  1744.  
  1745. /* ------------------------------------------------------------ */
  1746.  
  1747. /* You are at a ruler line.  Process it. */
  1748.  
  1749. void
  1750. B_RulerLine()
  1751.     {
  1752.     int num;
  1753.     int chr;
  1754.  
  1755.     cbuf->c.fill = 'W';
  1756.     BMoveBy(1);
  1757.     for (;;) {
  1758.         chr = NUL;
  1759.         switch (xtoupper(BGetCharAdv())) {
  1760.  
  1761.         case 'F':
  1762.             cbuf->c.fill = 'F';
  1763.             break;
  1764.  
  1765.         case 'L':
  1766.             BMoveBy(1);
  1767.             num = 0;
  1768.             while (xisdigit(chr = BGetCharAdv())) {
  1769.                 num = num * 10 + chr - '0';
  1770.                 }
  1771.             cbuf->c.left_margin = num;
  1772.             break;
  1773.  
  1774.         case 'N':
  1775.             cbuf->c.fill = 'N';
  1776.             break;
  1777.  
  1778.         case 'R':
  1779.             BMoveBy(1);
  1780.             num = 0;
  1781.             while (xisdigit(chr = BGetCharAdv())) {
  1782.                 num = num * 10 + chr - '0';
  1783.                 }
  1784.             cbuf->c.right_margin = num;
  1785.             break;
  1786.  
  1787.         case 'T':
  1788.             BMoveBy(1);
  1789.             num = 0;
  1790.             while (xisdigit(chr = BGetCharAdv())) {
  1791.                 num = num * 10 + chr - '0';
  1792.                 }
  1793.             cbuf->c.tab_spacing = num;
  1794.             break;
  1795.  
  1796.         case 'W':
  1797.             cbuf->c.fill = 'W';
  1798.             break;
  1799.  
  1800.         default:
  1801.             WFixup(&(cbuf->c));
  1802.             return;
  1803.             /*break;*/
  1804.             }
  1805.         if (chr == NL) break;
  1806.         }
  1807.     WFixup(&(cbuf->c));
  1808.     }
  1809.  
  1810.  
  1811. /* ------------------------------------------------------------ */
  1812.  
  1813. /* Set the modified flag to NEWFLAG. */
  1814.  
  1815. void
  1816. B_SetScreenMarks(newflag)
  1817.     FLAG newflag;
  1818.     {
  1819.     struct window *wptr;
  1820.  
  1821.     for (wptr = windows; wptr < &windows[NUMWINDOWS]; wptr++) {
  1822.         if (wptr->visible) B_SetScreenMarks2(wptr, newflag);
  1823.         }
  1824.     }
  1825.  
  1826.  
  1827. /* ------------------------------------------------------------ */
  1828.  
  1829. /* Set one windows' modified flags. */
  1830.  
  1831. void
  1832. B_SetScreenMarks2(wptr, newflag)
  1833.     struct window *wptr;
  1834.     FLAG newflag;
  1835.     {
  1836.     struct mark *mptr;
  1837.     struct mark *botmptr;
  1838.     struct mark *topmptr;
  1839.  
  1840.     botmptr = &screenmarks[wptr->bot];
  1841.     topmptr = &screenmarks[wptr->top];
  1842.  
  1843.     for (mptr = topmptr; mptr <= botmptr &&
  1844.         mptr->pptr != cur_page; ++mptr) ;
  1845.  
  1846.     if (mptr->bptr != cbuf) {
  1847.         mptr->is_mod = TRUE;
  1848.         }
  1849.     else if (mptr > botmptr) {
  1850.         for (mptr = topmptr; mptr <= botmptr &&
  1851.             (mptr->bptr != cbuf || BIsAfterMark(mptr));
  1852.             ++mptr) ;
  1853.         if (mptr > topmptr) {
  1854.             while ((--mptr)->bptr != cbuf) ;
  1855.             mptr->is_mod = TRUE;
  1856.             }
  1857.         }
  1858.     else    {
  1859.         while (mptr->pptr == cur_page &&
  1860.              mptr->mark_offset <= cur_pt_offset &&
  1861.              mptr <= botmptr)
  1862.             ++mptr;
  1863.  
  1864.         if (--mptr >= topmptr) mptr->is_mod = TRUE;
  1865.  
  1866.         if (newflag) {
  1867.             while (mptr > topmptr && mptr->pptr == cur_page &&
  1868.                  mptr->mark_offset == cur_pt_offset) {
  1869.                 (--mptr)->is_mod = TRUE;
  1870.                 }
  1871.             }
  1872.         }
  1873.     }
  1874.  
  1875.  
  1876. /* ------------------------------------------------------------ */
  1877.  
  1878. /* Check buffer data structures for consistency. */
  1879.  
  1880. #if defined(DEBUGGING_CODE)
  1881. void B_XVirtPage();
  1882.  
  1883. void
  1884. B_XDebug()
  1885.     {
  1886.     struct buffer *bptr;
  1887.     struct mark *mptr;
  1888.     struct virt_page *vptr;
  1889.     char buf[1000];
  1890.     int cnt;
  1891.     int cnt2;
  1892.  
  1893. /* check buffers */
  1894.     for (cnt = 0; cnt < NUMBUFFERS; cnt++) {
  1895.         bptr = &buffers[cnt];
  1896.         if (bptr->num_pages == 0) continue;    /* free */
  1897.  
  1898.         if (*bptr->fname == NUL) {
  1899.             xsprintf(buf, "buffer %d has no filename", cnt);
  1900.             DError(buf);
  1901.             }
  1902.         if (strlen(bptr->fname) > FNAMEMAX) {
  1903.             xsprintf(buf, "buffer %d has invalid filename", cnt);
  1904.             DError(buf);
  1905.             }
  1906.  
  1907.         for (cnt2 = 0; cnt2 < MAXMARK; cnt2++) {
  1908.             if (bptr->mptr == &marks[cnt2]) break;
  1909.             }
  1910.         if (cnt2 >= MAXMARK) {
  1911.             xsprintf(buf, "buffer %d has invalid mark", cnt);
  1912.             DError(buf);
  1913.             }
  1914.  
  1915.         B_XVirtPage(bptr->first, "buf first", cnt);
  1916.         B_XVirtPage(bptr->last, "buf last", cnt);
  1917.         B_XVirtPage(bptr->point_page, "buf point_page", cnt);
  1918.         for (vptr = bptr->first, cnt2 = 0; vptr != bptr->last;
  1919.              vptr = vptr->next, cnt2++) {
  1920.             B_XVirtPage(vptr, "buf page", cnt2);
  1921.             }
  1922.  
  1923.         if (bptr->point_offset < 0 || bptr->point_offset >= PAGESIZE) {
  1924.             xsprintf(buf, "buffer %d has invalid offset %d", cnt,
  1925.                 bptr->point_offset);
  1926.             DError(buf);
  1927.             }
  1928.         if (bptr->point_page->page_len &&
  1929.              bptr->point_offset > bptr->point_page->page_len + 1) {
  1930.             xsprintf(buf, "buffer %d has invalid offset %d of %d",
  1931.                 cnt, bptr->point_offset,
  1932.                 bptr->point_page->page_len);
  1933.             DError(buf);
  1934.             }
  1935.  
  1936.         if (bptr->num_pages < 0 || bptr->num_pages >= num_swap) {
  1937.             xsprintf(buf, "buffer %d has invalid num of pages %d",
  1938.                 cnt, bptr->num_pages);
  1939.             DError(buf);
  1940.             }
  1941.         }
  1942.  
  1943. /* check marks */
  1944.  
  1945.     for (cnt = 0; cnt < MAXMARK; cnt++) {
  1946.         mptr = &marks[cnt];
  1947.         if (mptr->pptr == NULL) continue;
  1948.         if (BIsFree(mptr->bptr)) continue;
  1949.  
  1950.         B_XVirtPage(mptr->pptr, "mark pptr", cnt);
  1951.  
  1952.         if (mptr->mark_offset < 0 || mptr->mark_offset >= PAGESIZE) {
  1953.             xsprintf(buf, "mark %d has invalid offset %d", cnt,
  1954.                 mptr->mark_offset);
  1955.             DError(buf);
  1956.             }
  1957.         if (mptr->pptr->page_len > 0 &&
  1958.              mptr->mark_offset > mptr->pptr->page_len + 1) {
  1959.             xsprintf(buf, "mark %d has invalid offset %d of %d",
  1960.                 cnt, mptr->mark_offset, mptr->pptr->page_len);
  1961.             DError(buf);
  1962.             }
  1963.         }
  1964.  
  1965. /* screen marks */
  1966.  
  1967.     for (cnt = 0; cnt < MAXSMARK - 1; cnt++) {
  1968.         mptr = &screenmarks[cnt];
  1969.         if (mptr->pptr == NULL) continue;
  1970.         if (BIsFree(mptr->bptr)) continue;
  1971.  
  1972.         B_XVirtPage(mptr->pptr, "scrnmark pptr", cnt);
  1973.  
  1974.         if (mptr->mark_offset < 0 || mptr->mark_offset >= PAGESIZE) {
  1975.             xsprintf(buf, "smark %d has invalid offset %d", cnt,
  1976.                 mptr->mark_offset);
  1977.             DError(buf);
  1978.             }
  1979.         if (mptr->pptr->page_len > 0 &&
  1980.              mptr->mark_offset > mptr->pptr->page_len + 1) {
  1981.             xsprintf(buf, "smark %d has invalid offset %d of %d",
  1982.                 cnt, mptr->mark_offset, mptr->pptr->page_len);
  1983.             DError(buf);
  1984.             }
  1985.         }
  1986.     }
  1987.  
  1988. void
  1989. B_XVirtPage(vptr, descr, cnt)
  1990.     struct virt_page *vptr;
  1991.     char *descr;
  1992.     int cnt;
  1993.     {
  1994.     char buf[1000];
  1995. /*
  1996.     struct virt_page *next;
  1997.     struct virt_page *prev;
  1998. */
  1999.     if (vptr->where != 'L' && vptr->where != 'M' && vptr->where != 'S') {
  2000.         xsprintf(buf, "virt page %s %d has invalid loc %c",
  2001.             descr, cnt, vptr->where);
  2002.         DError(buf);
  2003.         }
  2004.  
  2005.     if (vptr->page_num < 0 || vptr->page_num > num_swap) {
  2006.         xsprintf(buf, "virt page %s %d has invalid num %d",
  2007.             descr, cnt, vptr->page_num);
  2008.         DError(buf);
  2009.         }
  2010.  
  2011.     if (vptr->page_len < 0 || vptr->page_len > PAGESIZE) {
  2012.         xsprintf(buf, "virt page %s %d has invalid page size %d",
  2013.             descr, cnt, vptr->page_len);
  2014.         DError(buf);
  2015.         }
  2016.  
  2017.     if (vptr->gap_start < 0 ||
  2018.          (vptr->page_len > 0 && vptr->gap_start > vptr->page_len)) {
  2019.         xsprintf(buf, "virt page %s %d has invalid gap start %d",
  2020.             descr, cnt, vptr->gap_start);
  2021.         DError(buf);
  2022.         }
  2023.     }
  2024. struct buffer *cbuf;            /* the curent buffer */
  2025. struct mark *mark;            /* the current mark */
  2026. static struct virt_page *cur_page;    /* virtual page */
  2027. static int cur_pt_offset;        /* point offset */
  2028. static int cur_page_len;        /* page length */
  2029. static char *cur_cptr;            /* actual character */
  2030. static char *cur_page_start;        /* start of the page */
  2031. static char *cur_gap_start;        /* position of the gap */
  2032. static char *cur_gap_end;
  2033. static FLAG cur_is_mod;            /* is modified (dirty) */
  2034. static int cur_col = -1;        /* current column position */
  2035. static int savecol;
  2036. struct mark *getmark;
  2037. static struct phys_page *first_phys_page;  /* LRU chain of pages in memory */
  2038. static struct phys_page *last_phys_page;
  2039. #define SWAPMAPSIZE    ((long)SWAPMAX * 1024 / PAGESIZE)
  2040. static char swap_map[SWAPMAPSIZE];    /* swap file in use flags */
  2041. #endif
  2042.  
  2043. /* end of BUF.C -- Buffer Managment */
  2044.